package com.pinfly.common.util;

import java.util.ArrayList;
import java.util.List;

/**
 * Provides static methods for working with Collections.
 */
public class CollectionUtil
{
    /**
     * Splits a List into multiple lists, each which has a maximum of
     * maxRecordsInEachList elements. <br/>
     * Example:
     * <p>
     * <code><pre>
     * 
     *  List input = new ArrayList();
     *  input.add(&quot;one&quot;);
     *  input.add(&quot;two&quot;);
     *  input.add(&quot;three&quot;);
     *  input.add(&quot;four&quot;);
     *  input.add(&quot;five&quot;);
     *  
     *  List results = splitByElement(input, 3);
     *  
     *  results would contain the following lists:
     *  1 - {&quot;one&quot;, &quot;two&quot;, &quot;three&quot;}
     *  2 - {&quot;four&quot;, &quot;five&quot;}
     *  
     * </pre></code>
     * 
     * @param l The List to split
     * @param maxElementsInEachList The maximum number of records that can be in
     *            a returned List.
     * @return a List of List's, where the maximum number of elements in each
     *         sublist is defined by maxRecordsInEachList. If l is null, then an
     *         empty list is returned.
     */
    public static List splitByElement (List l, int maxElementsInEachList)
    {
        ArrayList result = new ArrayList ();

        if (l == null)
        {
            return (result);
        }

        int size = l.size ();

        int numLists = size / maxElementsInEachList;
        int offset = 0;
        for (int i = 0; i < numLists; i++)
        {
            List sublist = l.subList (offset, offset += maxElementsInEachList);
            result.add (sublist);
        }

        if (size % maxElementsInEachList > 0)
        {
            // One more list to pick up stragglers.
            List sublist = l.subList (offset, size);
            result.add (sublist);
        }

        return (result);

    }

    /**
     * Splits the specified list into at most maxNumberOfLists. The order of the
     * items in the list are preserved. Example:
     * <p>
     * <code><pre>
     * 
     *  List input = new ArrayList();
     *  input.add(&quot;one&quot;);
     *  input.add(&quot;two&quot;);
     *  input.add(&quot;three&quot;);
     *  input.add(&quot;four&quot;);
     *  input.add(&quot;five&quot;);
     *  input.add(&quot;six&quot;);
     *  input.add(&quot;seven&quot;);
     *  input.add(&quot;eight&quot;);
     *  input.add(&quot;nine&quot;);
     *  input.add(&quot;ten&quot;);
     *  
     *  List results = splitByNumberOfLists(input, 6);
     *  
     *  results would contain the following lists:
     *  1 - {&quot;one&quot;, &quot;two&quot;}
     *  2 - {&quot;three&quot;, &quot;four&quot;}
     *  3 - {&quot;five&quot;, &quot;six&quot;}
     *  4 - {&quot;seven&quot;, &quot;eight&quot;}
     *  5 - {&quot;nine&quot;}
     *  6 - {&quot;ten&quot;}
     *  
     * </pre></code>
     * 
     * @param l The list to split.
     * @param maxNumberOfLists The maximum number of return lists.
     * @return A List of List's.
     */
    public static List splitByNumberOfLists (List l, int maxNumberOfLists)
    {
        ArrayList result = new ArrayList ();

        if (l == null)
        {
            return (result);
        }

        int size = l.size ();

        int numberOfLists = 0;
        int sizeOfEachList = 0;
        int remain = 0;

        if (size < maxNumberOfLists)
        {
            numberOfLists = size;
            sizeOfEachList = 1;
        }
        else
        {
            sizeOfEachList = size / maxNumberOfLists;
            numberOfLists = maxNumberOfLists;
            remain = size % maxNumberOfLists;
        }

        int from = 0;
        int end = 0;

        for (int i = 0; i < numberOfLists; i++)
        {
            if (i < remain)
            {
                end = from + sizeOfEachList + 1;
            }
            else
            {
                end = from + sizeOfEachList;
            }

            List a = l.subList (from, end);
            result.add (a);

            from = end;
        }

        return (result);
    }

}